W2D5 学习手册 1.总览2.骨架3.保单Tool4.OCR 5.规则Tool6.schema7.Resource8.Prompt 9.分工10.调试11.可观测12.SpringAI 达标①达标②自测速记

FDE W2D5 学习手册 · MCP Server

W2 Day5 · B 级(必须掌握,面试高频)· 4h · 学完能亲手定义一个 MCP Server(医保场景:保单查询/OCR/规则校验 Tool + 文档 Resource + 审核 Prompt)

本日定位:W2D4 讲了 MCP 的协议模型与三种原语概念,今天落到"怎么实现一个 MCP Server"。重点在 Tool 的三段式(schema + 实现 + 注册)、Resource 与 Tool 的分工、与 Spring AI(Java)对接。候选人 Java 背景,会同时讲 Python SDK(官方参考)与 Java/Spring AI 落地。
学完能回答:① 怎么定义一个 MCP Tool(inputSchema 设计 + 函数实现 + 注册);② Resource 和 Tool 在 MCP 里的分工边界;③ 用 Python SDK 搭一个医保场景 Server 的骨架。
使用方法:通读原理 → 重点看「工程含义」「面试话术」「易错点」→ 做自测清单 → 配合《W2D5 评测题.md》。选中不熟的词可标注(左下★重要 / 右下📌待查)。

一、MCP Server 整体结构(医保场景)

一个 MCP Server = 一个进程(stdio)或 HTTP 服务,向 Client 暴露若干 Tools / Resources / Prompts。本日以"特药理赔审核"为例,目标 Server 包含:

能力类型作用
保单查询Tool按保单号查状态/额度/被保人
病历 OCRTool图片/PDF → 结构化文本
特药规则校验Tool输入诊断+药品 → 是否符合报销
保单文档Resource某保单的原始 PDF 文本(只读上下文)
理赔审核话术Prompt预置"标准审核提示词"模板
权威资源(中文/官方,非 OpenAI):
工程含义:Server 是"能力提供方",要把业务系统(保单库、OCR 引擎、规则引擎)包成标准 MCP 接口。医保团队已有 Java 后端,用 Spring AI 的 MCP Server 能力(@Tool / McpServer)更顺手;Python SDK 适合做原型与官方语义对齐。
一个 MCP Server 暴露 Tools/Resources/Prompts。医保例子:保单查询/OCR/规则校验做成 Tool,保单原文做成 Resource,审核话术做成 Prompt。Server 把"内部业务系统"包成标准协议接口,Client 无需懂内部实现。
① 别把所有能力都塞成一个 Tool——"查询+校验+写库"挤一个 Tool 既不好发现也难鉴权,应按职责拆。② Resource 不是"另一个 Tool",它不执行动作,只是把数据喂进上下文。③ 面试常考"这个需求该用 Tool 还是 Resource",见 s9。

二、用 Python SDK 搭 Server 骨架

2.1 选择实现方式

官方 Python SDK 提供高层封装 FastMCP(装饰器式,最常用)和低层 Server(手写 handler)。面试与落地推荐 FastMCP:用 @mcp.tool() / @mcp.resource() / @mcp.prompt() 声明能力,SDK 自动生成 schema 并注册。

2.2 最小骨架

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("insurance-claim-server")  # Server 名(serverInfo)

@mcp.tool()
def query_policy(policy_no: str) -> dict:
    """按保单号查询保单状态、额度、被保人。"""
    # 调内部保单库(此处省略)
    return {"policy_no": policy_no, "status": "active", "limit": 50000}

if __name__ == "__main__":
    mcp.run(transport="stdio")  # 或 transport="streamable-http"

2.3 运行与连接

python server.py → Host 以 stdio 拉起子进程 → initialize 握手 → tools/list 拿到 query_policy
骨架要"先跑通再丰富":先用一个 hello Tool 验证握手+list,再逐步加医保业务 Tool。生产里 Server 名、transport、能力要在配置里固化,并打日志便于排障。
Python SDK 用 FastMCP 最省事:建 mcp 实例,@mcp.tool() 装饰函数即注册,run(transport=...) 选 stdio 或 streamable-http。SDK 自动从类型注解生成 inputSchema,开发者只写业务逻辑。
① 别手写 JSON-RPC 协议细节(除非做极致定制),用 SDK 避免协议版本错配。② transport 名要对照固定验证版 2025-11-25(stdio / streamable-http),别用已弃用的 sse。③ 函数没有 docstring,模型就不知道这 Tool 干嘛、不会调——description 由 docstring 生成。

三、定义第一个 Tool:保单查询(schema + 实现 + 注册)

3.1 三段式

  1. schema(输入契约):由函数签名 + 类型注解 + docstring 生成 inputSchema(参数名、类型、必填、描述)。
  2. 实现(业务逻辑):函数体调内部保单库,返回结构化结果。
  3. 注册(暴露给 Client):@mcp.tool() 装饰即注册,握手后出现在 tools/list。

3.2 完善示例

@mcp.tool()
def query_policy(policy_no: str, fields: list[str] | None = None) -> dict:
    """
    按保单号查询保单信息。
    :param policy_no: 保单号,如 'PA2024-123456'
    :param fields: 可选,指定返回字段;为空返回全部
    :return: 含 status/limit/insured 的字典
    """
    rec = policy_db.get(policy_no)          # 内部查询(医保核心库)
    if not rec:
        return {"found": False, "policy_no": policy_no}
    return {"found": True, **rec}
定义一个 MCP Tool 就三步:① 写 inputSchema(靠类型注解+docstring,声明参数与含义);② 写实现(调内部系统、返回结构化数据);③ 注册(@mcp.tool() 装饰,自动进 tools/list)。模型靠 description 决定调不调、靠 schema 填参。
工程上 Tool 返回要稳定可解析:用 dict/Pydantic 模型,字段命名清晰,错误走结构化返回(如 {"found": False})而非抛未捕获异常。医保生产会对内部查询加超时、降级与审计。
① schema 的 description 决定调用准确率——"保单号"要写清格式示例,否则模型可能传错。② 返回尽量结构化、别返回超长自由文本,下游难解析。③ 别在 Tool 里做权限判断——那是 Host 层职责(见 D4 Q9/Q13)。

四、实现 OCR Tool

OCR Tool 把病历/发票图片或 PDF 转成结构化文本,供后续规则校验与生成使用。注意它是有副作用吗——OCR 本身是只读识别(readOnlyHint=true),但可能写临时文件。

@mcp.tool()
def ocr_document(image_path: str) -> dict:
    """
    对病历/发票图片做 OCR,返回结构化文本与关键字段。
    :param image_path: 图片或 PDF 路径
    :return: { text, fields: {patient, hospital, date} }
    """
    text = ocr_engine.recognize(image_path)   # 调用 OCR 引擎
    return {"text": text, "fields": extract_fields(text)}
医保落地:OCR 引擎可能是内部 Java 服务或本地 PaddleOCR。用 stdio 本地跑 OCR 省去网络与鉴权;若 OCR 是共享 GPU 服务,则单独做 Remote HTTP Server。OCR 输出要进"引用溯源"(原文对应哪段),供理赔结论回溯。
OCR Tool = 图片/PDF → 结构化文本。标注 readOnlyHint=true(只识别不写业务库)。工程上 OCR 结果要保留原文用于引用溯源,避免"模型凭空编诊断"。
① OCR 结果有误差,别直接当事实喂给规则校验——要保留置信度/原文,让下游可质疑。② 大文件 OCR 要设超时与分片,别卡死 Server。③ readOnlyHint 只是提示,真实写临时文件也要受 Server 文件系统权限约束(D4 s12)。

五、实现特药规则校验 Tool

规则校验 Tool 是"理赔大脑":输入诊断、药品、既往史,对照特药目录/适应症/医保限制,输出是否可报销及理由。

@mcp.tool()
def check_drug_rule(diagnosis: str, drug_name: str, policy_no: str) -> dict:
    """
    校验某特药是否符合报销规则。
    :param diagnosis: 诊断名称
    :param drug_name: 药品名(如 '奥希美替尼')
    :param policy_no: 保单号(用于额度关联)
    :return: { covered: bool, reason, max_amount }
    """
    rule = drug_rule_db.lookup(drug_name, diagnosis)   # 特药目录+适应症
    if not rule or not rule.covered:
        return {"covered": False, "reason": "不在适应症范围", "max_amount": 0}
    return {"covered": True, "reason": rule.reason, "max_amount": rule.limit}
规则校验是"确定性问题",要低随机(T=0)、可解释。返回的 reason 要能回溯到具体条款(引用溯源),供拒付时向客户解释。医保场景规则常变,把规则外置到 DB/配置,Tool 只做"查+算"。
规则校验 Tool:输入诊断+药品+保单号,对照特药目录输出"是否报销+理由+上限"。它是确定逻辑,返回要带可解释的 reason 与引用,拒付时能讲清依据。
① 规则逻辑别硬编码进 Tool——要外置(DB/配置),否则改规则要发版。② 返回的 covered=false 要区分"真不符合"和"信息不足",避免模型把"查不到"当"不报销"。③ 规则 Tool 是 readOnly(只查只算),但"提交理赔结论"才是写操作,要分开(D4 s9/s10)。

六、inputSchema 设计要点

要点做法为什么
参数描述清晰docstring 写清格式/示例/取值范围模型靠描述选参、填参
类型精确用 str/int/bool/枚举,必要时 Pydantic生成正确 schema,减少填错
必填 vs 可选无默认=必填,有默认=可选影响模型是否需补参
枚举约束用 Literal 限制取值防止模型传非法值
避免超长自由文本大文本走 Resource,Tool 只收引用Tool 参数应精简
from typing import Literal
@mcp.tool()
def check_drug_rule(diagnosis: str, drug_name: str,
                    region: Literal["北京","上海","全国"] = "全国") -> dict:
    ...
schema 质量是调用准确率的命门。医保场景参数多(诊断/药品/地区/保单),用 Literal 枚举把"地区"锁死,能大幅降低模型传错。生产会把 schema 当"接口契约"评审,而非随手写。
inputSchema 设计四要点:描述写清(含示例)、类型精确、必填/可选分明、非法值用枚举锁死。schema 是模型与 Tool 的"契约",质量直接决定调用准确率。
① 参数描述含糊 → 模型选错 Tool 或填错参,这是 MCP 调用失败的头号原因。② 别把整篇病历塞进 Tool 参数——长文本用 Resource 传引用。③ schema 改了要同步版本,避免 Client 缓存的旧 schema 错配。

七、定义 Resource:保单文档

Resource 是只读数据/上下文,由应用注入模型上下文,而非模型触发执行。用 @mcp.resource() 声明,URI 作为句柄。

@mcp.resource("policy://{policy_no}/document")
def policy_document(policy_no: str) -> str:
    """返回某保单的原始条款文本(只读上下文)。"""
    return policy_store.load_text(policy_no)

Client/Host 通过 resources/read 按 URI 读取,把文本塞进提示上下文,让模型"看到原文"再做判断(配合引用溯源)。

医保场景:保单原文、特药目录、医保政策条文都适合做成 Resource——它们是"知识",不是"动作"。Resource 让模型基于真实文本推理,减少编造;同时支持引用(哪段条款支持结论)。
Resource = 只读数据,用 @mcp.resource("uri") 声明,Host 通过 resources/read 按 URI 读入上下文。保单原文/特药目录/政策条文都该做成 Resource——它们是"知识"不是"动作"。
① Resource 不是 Tool,模型不能"调用"它执行,只能由应用读入上下文——别混淆触发方式。② Resource 内容可能很大,要分页/截断,别一次塞爆上下文。③ Resource 的 URI 设计要有规范(如 policy://{no}),方便 Host 引用与缓存。

八、定义 Prompt:理赔审核模板

Prompt 是用户可选的提示词模板,带参数,由用户在 Host 里点选填入。用 @mcp.prompt() 声明。

@mcp.prompt()
def claim_review_prompt(policy_no: str, drug_name: str) -> str:
    """生成标准理赔审核提示词。"""
    return f"""你是特药理赔审核员。请基于保单 {policy_no} 与药品 {drug_name}:
1) 核对诊断与药品适应症;
2) 引用保单条款给出能否报销;
3) 不确定时明确拒答并说明缺什么材料。"""
Prompt 模板把"专家经验"沉淀成可复用范式,降低前端每次拼 prompt 的成本,也保证审核口径一致(合规需要)。医保团队可把"审核 SOP"固化成多个 Prompt 模板。
Prompt = 用户选的提示词模板(@mcp.prompt),带参数、可复用。把"理赔审核 SOP"固化成模板,保证口径一致、降低拼 prompt 成本,是合规资产。
① Prompt 模板是 user-controlled,不是模型自动调——别和 Tool 混淆。② 模板里要内置"不确定就拒答"约束,防止模型硬编(见 D6 拒答)。③ 模板参数要校验,避免注入(用户传恶意内容拼进 prompt)。

九、Resource 与 Tool 的分工边界(达标线②)

维度ToolResource
本质动作(执行函数)数据(只读上下文)
触发方模型(推理中自主决定)应用/Host(读入上下文)
副作用可有(写/算/调外部)
返回结构化结果供下游用文本/数据供模型"阅读"
医保例子查保单、OCR、规则校验保单原文、特药目录
判断标准:要不要"执行一个动作/产生副作用" → Tool;只是"把一段知识放进上下文" → Resource
分工一句话:Tool 是"做"(模型触发、可有副作用),Resource 是"给"(应用注入、只读知识)。该执行动作(查/OCR/校验)用 Tool;该提供原文/目录(保单文本、特药表)用 Resource。混淆二者会导致权限错配与发现混乱。
① "查一个值"看似读,但若是"模型要主动调业务系统拿结果"就用 Tool;若是"静态知识直接进上下文"才用 Resource。② 把 Resource 当 Tool 用会丢失动作语义与鉴权边界;反之把 Tool 当 Resource 会让模型无法触发。③ 面试常考这个边界,要结合"触发方+副作用"判断。

十、本地调试与 tools/list 验证

10.1 调试步骤

  1. 单独跑 Server,确认进程正常启动、无 import 错误。
  2. 用 MCP Inspector / SDK 客户端发起 initialize,确认握手成功、版本对齐。
  3. tools/list 确认三个 Tool + Resource + Prompt 都在,schema 正确。
  4. tools/call 实测参数与返回,检查错误路径(如保单不存在)。

10.2 常见坑

医保生产:Server 要有健康检查与结构化错误(如 {"error":"policy_not_found"}),并接日志/监控。tools/list 结果建议缓存(按 Server 版本失效),减少握手开销。
调试四步:跑进程 → initialize 验握手 → tools/list 验能力+schema → tools/call 实测。常见坑:docstring 空导致不调用、返回不可序列化、异常未捕获。生产要结构化错误+日志+监控。

十一、错误处理与可观测

可观测是生产 Server 的底线。理赔涉及钱与客户隐私,每次 Tool 调用都要可回溯、可审计;异常要"fail visible"(明确报错)而非静默返回错数据。
MCP Server 可观测三件套:结构化错误(不抛裸异常)、超时降级、日志+审计 Trace。医保场景每次调用留痕,异常要 fail visible 而非静默错返。
① 别"静默返回错误数据"——模型会当真,导致错赔。② 审计日志别记明文隐私(脱敏)。③ 超时设置要合理,OCR 大图可比查询类更长。

十二、与 Spring AI(Java)对接:候选人落地路径

候选人是 Java 背景,医保主力后端是 Spring。Spring AI 提供 MCP Server 能力:用 @Tool / ToolCallback 声明工具,框架负责协议层。B站 Spring AI 第 49–56 集 MCP 全套(BV1GfyGBqEm6)讲透 Java 侧实现。

@Tool(description = "按保单号查询保单状态与额度")
public Map<String,Object> queryPolicy(@ToolParam("保单号") String policyNo) {
    return policyService.query(policyNo);   // 复用现有 Java 保单服务
}
Java 落地优势:直接复用医保现有 Spring 微服务(保单库、规则引擎),把"已有方法"用 @Tool 包一层即变成 MCP 能力,几乎零重写。Python SDK 适合做原型与官方语义对齐。
工程策略:核心业务用 Spring AI MCP Server(复用 Java 资产);探索性/算法型 Tool(如 OCR 后处理)可用 Python Server,由 Host 同时连多个 Client。选型看团队栈,不强行统一语言。
Java 候选人用 Spring AI 做 MCP Server 最顺:@Tool 注解把现有 Spring 方法包成 MCP 能力,复用保单/规则微服务。Python SDK 用于原型。B站 BV1GfyGBqEm6 第49-56集讲 Java 侧全套。
① 别以为"必须用 Python"——MCP 是协议,任何语言都能实现,Java 用 Spring AI 完全够。② @Tool 的 description 同样关键(模型靠它选)。③ 复用现有服务时要保留原有权限/审计,别因包了 MCP 就绕过。

十三、面试达标线①:怎么定义一个 MCP Tool

定义 Tool = ①写 inputSchema(类型注解+docstring,声明参数与含义) → ②写实现(调内部系统、返回结构化结果) → ③注册(@mcp.tool() 装饰,进 tools/list)
环节必须能讲清
schema参数名/类型/必填/描述由注解+docstring 生成;枚举锁非法值
实现调内部业务、返回可解析结构化结果、错误结构化返回
注册@mcp.tool()(Python)/ @Tool(Spring AI)装饰即注册,握手后进 tools/list
医保例保单查询/OCR/规则校验三个 Tool 的 schema+实现要点
达标线①核心:能完整讲出 Tool 三段式(schema→实现→注册),并以保单查询 Tool 为例说明参数设计、返回结构与注册方式。这是"会不会动手"的硬指标。

十四、面试达标线②:Resource 与 Tool 的分工

Tool = 做(模型触发、可有副作用、返回结构化结果) | Resource = 给(应用注入、只读知识、进上下文)
达标线②核心:能用"触发方+副作用+本质"三维讲清 Tool 与 Resource 边界,并正确把医保场景能力归类。混淆二者会导致权限错配与发现混乱。

十五、W2D5 自测清单

十六、高频面试题速记卡

Q:定义一个 MCP Tool 分几步?
三步:①写 inputSchema(注解+docstring 声明参数/含义);②写实现(调内部系统、返回结构化结果);③注册(@mcp.tool() 装饰,进 tools/list)。
Q:Tool 的 schema 从哪来?
由函数类型注解 + docstring 生成(FastMCP);参数描述与枚举决定模型选参填参准确率。description 缺失=模型不调。
Q:Resource 和 Tool 什么区别?
Tool=做(模型触发、可有副作用);Resource=给(应用注入、只读知识进上下文)。判定看"是否执行动作/产生副作用"。
Q:保单原文该做成 Tool 还是 Resource?
Resource——它是只读知识,由 Host 读入上下文供模型"看原文",不是模型触发的动作。
Q:规则校验 Tool 要注意什么?
确定性逻辑用低随机(T=0)、返回带可解释 reason 与引用、规则外置(DB/配置)、区分"不符合"与"信息不足"。
Q:Java 怎么做 MCP Server?
用 Spring AI:@Tool 注解把现有 Spring 方法包成 MCP 能力,复用保单/规则微服务。Python SDK 用于原型。
Q:调试 MCP Server 四步?
跑进程 → initialize 验握手/版本 → tools/list 验能力+schema → tools/call 实测(含错误路径)。
Q:MCP Server 可观测三件套?
结构化错误(不抛裸异常)、超时降级、日志+审计 Trace。医保场景每次调用留痕,异常 fail visible。
Q:Prompt 模板谁触发?
user-controlled——用户在 Host 里点选并填参,非模型自动调用,用于固化审核 SOP 保证口径一致。
Q:为什么别把所有能力塞一个 Tool?
难发现、难鉴权、难评测。应按职责拆(查询/OCR/校验分离),提升调用准确率与权限边界。
FDE W2D5 学习手册 · MCP Server(面试级)· 配合《W2D5 评测题.md》自测
📌 待查★ 重要